/*
 *  Copyright (c) Iris Dev. team. All rights reserved.
 *  See http://www.communico.pro/license for details.
 *
 */
#ifndef _AS_MEMCACHED_OBJECT_HPP__
#define _AS_MEMCACHED_OBJECT_HPP__ 1

/**
  @file ASMemcachedObject.hpp
  @brief Application server example object
*/
#include <ASObject.hpp>
#include <STLString.hpp>

#include "ASMemcached.hpp"
#include "ASConsistentHash.hpp"

using namespace CAS;

namespace CAS_MOD
{

/**
  @class ASObject ASObject.hpp <ASObject.hpp>
  @brief Application server object
*/
class ASMemcachedObject:
  public ASObject
{
public:
	/**
	  @var enum eSerializer { NONE, JSON, PERL_STORABLE, PHP_SERIALIZE, PYTHON_MARSHALL };
	  @brief Serialization method
	*/
	enum eSerializer { NONE, JSON };

	/**
	  @brief Constructor
	  @param eISerializationMethod - serialization method
	  @param iIErrorTimeout - error timeout, msec
	  @param iMaxContinuumElements - number of elements in continuum
	*/
	ASMemcachedObject(const eSerializer  & eISerializationMethod = JSON,
	                  const INT_32         iIErrorTimeout        = 10000,
	                  const UINT_32        iMaxContinuumElements = 100,
	                  const INT_32         iICompressThreshold   = 0,
	                  const W_FLOAT        dICompressRatio       = 0.0);

	/**
	  @brief Add server
	  @param sHost - memcached host or IP address or unix socket
	  @param iPort - memcached port, if need
	  @param iProto - protocol: TCP or UDP
	  @param dWeight - weight of server
	  @param iConnTimeout - connection timeout, msec
	  @param iIOTimeout - input/output timeout, msec
	  @return Memcached server Id
	*/
	INT_32 AddServer(const STLW::string  & sHost,
	                 const INT_32          iPort,
	                 const INT_32          iProto,
	                 const W_FLOAT         dWeight      = 1.0,
	                 const INT_32          iConnTimeout = 10000,
	                 const INT_32          iIOTimeout   = 1000);


	/**
	  @Brief Get value from memcached
	  @param sKey - key to get
	  @param oCDT - output value
	  @param iCASUnique - CAS unique
	  @return Result of query, one of eQueryResult states
	*/
	Memcached::eQueryResult Gets(const STLW::string  & sKey,
	                             CTPP::CDT           & oCDT,
	                             UINT_64             & iCASUnique);

	/**
	  @brief Check And Set (CAS) value
	  @param sKey - key to get
	  @param oCDT - output value
	  @param iCASUnique - CAS unique
	  @param iExpires - expiration time
	  @return Result of query, one of eQueryResult states
	*/
	Memcached::eQueryResult Cas(const STLW::string  & sKey,
	                            const CTPP::CDT     & oCDT,
	                            const UINT_64       & iCASUnique,
	                            INT_32                iExpires = 0);

	/**
	  @brief Get value from memcached
	  @param sKey - key to get
	  @param oCDT - output value
	  @return Result of query, one of eQueryResult states
	*/
	Memcached::eQueryResult Get(const STLW::string  & sKey,
	                            CTPP::CDT           & oCDT);

	/**
	  @brief Set value
	  @param sKey - memcached key
	  @param oCDT - value to set
	  @param iExpires - expiration time
	  @return Result of query, one of eQueryResult states
	*/
	Memcached::eQueryResult Set(const STLW::string  & sKey,
	                            const CTPP::CDT     & oCDT,
	                            const INT_32          iExpires = 0);

	/**
	  @brief Add value
	  @param sKey - memcached key
	  @param oCDT - value to add
	  @param iExpires - expiration time
	  @return Result of query, one of eQueryResult states
	*/
	Memcached::eQueryResult Add(const STLW::string  & sKey,
	                            const CTPP::CDT     & oCDT,
	                            const INT_32          iExpires = 0);

	/**
	  @brief Increment/add value
	  @param sKey - memcached key
	  @param iValue - value to increment
	  @return Result of query, one of eQueryResult states
	*/
	Memcached::eQueryResult Incr(const STLW::string  & sKey,
	                             INT_64              & iValue);

	/**
	  @brief Decrement/substract value
	  @param sKey - memcached key
	  @param iValue - value to decrement
	  @return Result of query, one of eQueryResult states
	*/
	Memcached::eQueryResult Decr(const STLW::string  & sKey,
	                             INT_64              & iValue);

	/**
	  @brief Replace value
	  @param sKey - memcached key
	  @param oCDT - value to replace
	  @param iExpires - expiration time
	  @return Result of query, one of eQueryResult states
	*/
	Memcached::eQueryResult Replace(const STLW::string  & sKey,
	                                const CTPP::CDT     & oCDT,
	                                const INT_32          iExpires = 0);

	/**
	  @brief Append data to string stored in cache
	  @param sKey - memcached key
	  @param oCDT - value to append
	  @param iExpires - expiration time
	  @return Result of query, one of eQueryResult states
	*/
	Memcached::eQueryResult Append(const STLW::string  & sKey,
	                               const CTPP::CDT     & oCDT,
	                               const INT_32          iExpires = 0);

	/**
	  @brief Prepend value to string stored in cache
	  @param sKey - memcached key
	  @param oCDT - value to prepend
	  @param iExpires - expiration time
	  @return Result of query, one of eQueryResult states
	*/
	Memcached::eQueryResult Prepend(const STLW::string  & sKey,
	                                const CTPP::CDT     & oCDT,
	                                const INT_32          iExpires = 0);

	/**
	  @brief Delete value from cache
	  @param sKey - memcached key
	  @return Result of query, one of eQueryResult states
	*/
	Memcached::eQueryResult Del(const STLW::string & sKey);

	/**
	  @brief Get Unix error code
	  @param iServerId - memcached server id
	  @return Unix error code
	*/
	INT_32 GetError(const UINT_32 iServerId);

	/**
	  @brief A virtual destructor
	*/
	~ASMemcachedObject() throw();

private:
	/**
	  @struct MemcachedData ASMemcachedObject.hpp <ASMemcachedObject.hpp>
	  @brief Memcached connector data
	*/
	struct MemcachedData
	{
		/** Host name or IP address */
		STLW::string     host;
		/** Port                    */
		INT_32           port;
		/** Protocol                */
		INT_32           proto;
		/** Memcached connector     */
		Memcached      * memcached;
		/** Weight                  */
		W_FLOAT          weight;
		/** Timestamp of last error */
		UINT_64          last_error_ts;
	};

	/** Serialization method           */
	const eSerializer  eSerializationMethod;
	/** Connection timeout */
	INT_32             iConnTimeout;
	/** I/O timeout        */
	INT_32             iIOTimeout;
	/** Error timeout      */
	INT_64             iErrorTimeout;
	/** Compression threshold */
	INT_32             iCompressThreshold;
	/** Compression ratio */
	W_FLOAT            dCompressRatio;

	/** List of memcached servers      */
	ConsistentHash<MemcachedData>  oMemcachedList;
	/** List of servers                */
	STLW::vector<Memcached *>      vServers;

	ASMemcachedObject(const ASMemcachedObject & oRhs);
	ASMemcachedObject & operator=(const ASMemcachedObject & oRhs);

	/**
	  @brief Get object type
	  @return human-readable type of object
	*/
	CCHAR_P GetObjectType() const;

	/**
	  @brief Get object name
	  @return human-readable name of object
	*/
	CCHAR_P GetObjectName() const;

	/**
	  @berif Serialize CDT to string with specified serialization method
	  @param oCDT - object need to serialize
	  @param sData - destination string
	*/
	INT_64 SerializeCDT(const CTPP::CDT  & oCDT,
	                    STLW::string     & sData) const;

	/**
	  @brief Un-Serialize CDT to string with specified serialization method
	  @param oCDT - object need to restore
	  @param sData - raw data
	*/
	void RestoreCDT(const STLW::string  & sData,
	                CTPP::CDT           & oCDT) const;

	/**
	  @brief Compress value
	*/
	void CompressValue(STLW::string  & sSerializedValue,
	                   UINT_64       & iFlags) const;


	/**
	  @brief Decompress value
	*/
	void DecompressValue(STLW::string  & sSerializedValue,
	                     UINT_64       & iFlags) const;

	/**
	  @brief Get Memcached server
	  @param sKey - key
	  @return Pointer to active memcached connection
	*/
	Memcached * GetMemcachedServer(const STLW::string  & sKey);
};

} // namespace CAS_MOD
#endif // _AS_MEMCACHED_OBJECT_HPP__
// End.
